#pragma once

#include <iostream>
#include <string>
#include <thread>
#include "inetapi.hpp"
#include "easylog.hpp"
#include "protocol.hpp"
#include "task.hpp"

namespace tcp
{
using namespace proto;

class tcp_server : public inet::tcp::server
{
public:
    using func_t = std::function<response(const request&)>;

public:
    tcp_server(func_t cb, uint16_t port) : _cb(cb), server(port)
    {}

    ~tcp_server()
    {}

    void init()
    {}

    void start()
    {
        while (true)
        {
            std::string cip;
            uint16_t cport;
            int sock = accept(&cip, &cport);
            if (sock < 0)
                continue;

            DEBUG("get a new client: [%s:%d]", cip.c_str(), cport);

            std::thread th(&tcp_server::service, this, sock, cip, cport);
            th.detach();
        }
    }

    void service(int sock, const std::string& ip, uint16_t port)
    {
        while (true)
        {
            std::string msg = request::recvpack(sock);

            request req;
            req.deserialize(msg);

            std::string rspstr = _cb(req).serialize();
            send(sock, rspstr);
        }
    }

private:
    func_t _cb;
};
} // namespace tcp
